package com.model;

import com.model.math.Point3D;

/**
 * 模型包围盒计算器
 * 用于计算3D模型在给定变换（缩放、旋转）下的外包围盒
 */
public class ModelBoundingBox {
    private static final boolean DEBUG = true;
    
    private void debugPrint(String message) {
        if (DEBUG) {
            System.out.println("[ModelBoundingBox] " + message);
        }
    }
    
    // 模型原始数据
    private double latitude;    // 纬度（度）
    private double longitude;   // 经度（度）
    private double height;      // 高度（米）
    private double rotationX;   // X轴旋转角（弧度）
    private double rotationY;   // Y轴旋转角（弧度）
    private double rotationZ;   // Z轴旋转角（弧度）
    private double scale;       // 缩放倍率
    
    /**
     * 构造函数
     * @param latitude 纬度（度）
     * @param longitude 经度（度）
     * @param height 高度（米）
     * @param rotationX X轴旋转角（度）
     * @param rotationY Y轴旋转角（度）
     * @param rotationZ Z轴旋转角（度）
     * @param scale 缩放倍率
     */
    public ModelBoundingBox(double latitude, double longitude, double height,
                           double rotationX, double rotationY, double rotationZ,
                           double scale) {
        this.latitude = latitude;
        this.longitude = longitude;
        this.height = height;
        // 将角度转换为弧度
        this.rotationX = Math.toRadians(rotationX);
        this.rotationY = Math.toRadians(rotationY);
        this.rotationZ = Math.toRadians(rotationZ);
        this.scale = scale;
    }
    
    /**
     * 计算模型的外包围盒
     * @param modelVertices 模型顶点数组
     * @return 计算得到的外包围盒
     */
    public BoundingBox calculateVerticalBoundingBox(Point3D[] modelVertices) {
        // 首先应用缩放变换
        Point3D[] scaledVertices = applyScale(modelVertices);
        
        // 然后应用旋转变换
        Point3D[] rotatedVertices = applyRotation(scaledVertices);
        
        // 最后计算外包围盒
        return calculateBoundingBox(rotatedVertices);
    }
    
    /**
     * 对顶点应用缩放变换
     */
    private Point3D[] applyScale(Point3D[] vertices) {
        Point3D[] result = new Point3D[vertices.length];
        for (int i = 0; i < vertices.length; i++) {
            result[i] = new Point3D(
                vertices[i].x * scale,
                vertices[i].y * scale,
                vertices[i].z * scale
            );
        }
        return result;
    }
    
    /**
     * 对顶点应用旋转变换
     * 按照X->Y->Z的顺序进行旋转
     */
    private Point3D[] applyRotation(Point3D[] vertices) {
        debugPrint("开始应用旋转变换");
        Point3D[] result = new Point3D[vertices.length];
        for (int i = 0; i < vertices.length; i++) {
            // 应用X轴旋转（绕X轴旋转，影响Y和Z坐标）
            double y1 = vertices[i].y * Math.cos(rotationX) - vertices[i].z * Math.sin(rotationX);
            double z1 = vertices[i].y * Math.sin(rotationX) + vertices[i].z * Math.cos(rotationX);
            
            // 应用Y轴旋转（绕Y轴旋转，影响X和Z坐标）
            double x2 = vertices[i].x * Math.cos(rotationY) + z1 * Math.sin(rotationY);
            double z2 = -vertices[i].x * Math.sin(rotationY) + z1 * Math.cos(rotationY);
            
            // 应用Z轴旋转（绕Z轴旋转，影响X和Y坐标）
            double x3 = x2 * Math.cos(rotationZ) - y1 * Math.sin(rotationZ);
            double y3 = x2 * Math.sin(rotationZ) + y1 * Math.cos(rotationZ);
            
            result[i] = new Point3D(x3, y3, z2);
        }
        debugPrint("旋转变换完成");
        return result;
    }
    
    /**
     * 计算顶点集合的外包围盒
     */
    private BoundingBox calculateBoundingBox(Point3D[] vertices) {
        // 初始化最大最小值
        double minX = Double.MAX_VALUE;
        double minY = Double.MAX_VALUE;
        double minZ = Double.MAX_VALUE;
        double maxX = -Double.MAX_VALUE;
        double maxY = -Double.MAX_VALUE;
        double maxZ = -Double.MAX_VALUE;
        
        // 遍历所有顶点找出最大最小坐标值
        for (Point3D vertex : vertices) {
            minX = Math.min(minX, vertex.x);
            minY = Math.min(minY, vertex.y);
            minZ = Math.min(minZ, vertex.z);
            maxX = Math.max(maxX, vertex.x);
            maxY = Math.max(maxY, vertex.y);
            maxZ = Math.max(maxZ, vertex.z);
        }
        
        // 创建并返回包围盒
        return new BoundingBox(
            new Point3D(minX, minY, minZ),
            new Point3D(maxX, maxY, maxZ)
        );
    }
    
    // 添加 getter 方法
    public double getLatitude() {
        return latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public double getRotationX() {
        return rotationX;
    }

    public double getRotationY() {
        return rotationY;
    }

    public double getRotationZ() {
        return rotationZ;
    }

    public double getScale() {
        return scale;
    }

    public double getHeight() {
        return height;
    }

    /**
     * 应用所有变换（缩放和旋转）到顶点
     */
    public Point3D[] applyTransformation(Point3D[] vertices) {
        debugPrint("\n=== 开始应用模型变换 ===");
        debugPrint(String.format("变换参数: 缩放=%.2f", scale));
        debugPrint(String.format("旋转角度: X=%.2f°, Y=%.2f°, Z=%.2f°", 
            Math.toDegrees(rotationX),
            Math.toDegrees(rotationY),
            Math.toDegrees(rotationZ)));

        // 在缩放变换后添加验证
        Point3D[] scaledVertices = applyScale(vertices);
        debugPrint("\n缩放变换验证:");
        debugPrint("原始第一个顶点: " + vertices[0]);
        debugPrint("缩放后第一个顶点: " + scaledVertices[0]);

        // 在旋转变换后添加验证
        Point3D[] rotatedVertices = applyRotation(scaledVertices);
        debugPrint("\n旋转变换验证:");
        debugPrint("旋转后第一个顶点: " + rotatedVertices[0]);
        debugPrint("验证垂直方向是否保持正确");

        return rotatedVertices;
    }
} 